#include <phonon>
#include <QBrush>
#include <QColor>
#include <QCoreApplication>
#include <QDir>
#include <QMap>
#include <QStringList>
#include <QTableWidgetItem>
#include <QtGlobal>
#include <QThread>
#include <QTimer>
#include "mainwidget.h"
#include "ui_mainwidget.h"

#define STRINGIFY(str) #str

enum Time  { Past = 0, Present, Future };
enum Sentence  { Question = 0, Statement, Negation };
enum Pronoun  { I = 0, You, He, She, We, They };
static const char* Pronouns[] = {
  STRINGIFY(I),
  STRINGIFY(You),
  STRINGIFY(He),
  STRINGIFY(She),
  STRINGIFY(We),
  STRINGIFY(They)
};
const int PronounCount = sizeof(Pronouns)/sizeof(Pronouns[0]);

MainWidget::MainWidget(QWidget *parent)
  : QWidget(parent), ui(new Ui::MainWidget)
  , m_done(true)
  , m_pronoun(-1), m_verb(-1), m_time(-1), m_sentence(-1)
  , m_task(0), m_answer(0)
  , m_media(0), m_output(0)
{
  ui->setupUi(this);

  ui->matrix->setRowCount(3);
  ui->matrix->setColumnCount(3);

  QStringList list;
  list.push_back(STRINGIFY(Question));
  list.push_back(STRINGIFY(Statement));
  list.push_back(STRINGIFY(Negation));
  ui->matrix->setVerticalHeaderLabels(list);

  list.clear();
  list.push_back(STRINGIFY(Past));
  list.push_back(STRINGIFY(Present));
  list.push_back(STRINGIFY(Future));
  ui->matrix->setHorizontalHeaderLabels(list);

  ui->matrix->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
  ui->matrix->verticalHeader()->setResizeMode(QHeaderView::Stretch);

  m_media = new Phonon::MediaObject(this);
  m_output = new Phonon::AudioOutput(Phonon::MusicCategory, this);
  Phonon::createPath(m_media, m_output);
  connect(m_media, SIGNAL(finished()), this, SLOT(on_finished()));

  scan();
  step();

  qsrand(QTime::currentTime().msec());
  m_qtime.start();
  startTimer(100);
}

MainWidget::~MainWidget()
{
  delete ui;
}

void MainWidget::scan()
{
  QDir dir(QCoreApplication::applicationDirPath() + "/audio/verb");
  QStringList files = dir.entryList(QStringList("*.mp3"), QDir::Files);
  QMap<QString, verb> verbs;
  for (auto iter = files.begin(); iter != files.end(); ++iter)
  {
    QStringList elements = iter->split('.');
    elements.removeLast();
    if (elements.size() == 3)
    {
      verbs[elements[0]].main = elements[0];
      if (elements[1] == "ts") verbs[elements[0]].third_singular = elements[2];
      else if (elements[1] == "p") verbs[elements[0]].past = elements[2];
    }
  }
  m_verbs = verbs.values();
}

void MainWidget::step(int time, int sentence)
{
  ui->matrix->clearContents();
  QTableWidgetItem* item = new QTableWidgetItem;
  item->setTextAlignment(Qt::AlignCenter);
  m_media->stop();
  m_files.clear();

  if (m_done)
  {
    m_pronoun = qrand() % PronounCount;
    m_verb = qrand() % m_verbs.count();
    m_time = time < 0? (qrand() % 3): time;
    m_sentence = sentence < 0? (qrand() % 3): sentence;
    ++m_task;

    QString text;
    text += Pronouns[m_pronoun];
    text += "\n";
    text += m_verbs[m_verb].main;
    item->setText(text);
    item->setForeground(QBrush(Qt::darkRed));

  }
  else
  {
    QString text, path(QCoreApplication::applicationDirPath() + "/audio");
    QString
      did_mp3(path + "/auxiliary/did.mp3"),
      didn_t_mp3(path + "/reduction/didn_t.mp3"),
      do_mp3(path + "/auxiliary/do.mp3"),
      does_mp3(path + "/auxiliary/does.mp3"),
      don_t_mp3(path + "/reduction/don_t.mp3"),
      doesn_t_mp3(path + "/reduction/doesn_t.mp3"),
      pronoun_mp3(path + "/pronoun/" + QString(Pronouns[m_pronoun]).toLower() + ".mp3"),
      pronoun_ll_mp3(path + "/reduction/" + QString(Pronouns[m_pronoun]).toLower() + "_ll.mp3"),
      verb_mp3(path + "/verb/" + m_verbs[m_verb].main + ".mp3"),
      verb_past_mp3(path + "/verb/" + m_verbs[m_verb].main + ".p." + m_verbs[m_verb].past + ".mp3"),
      verb_third_singular_mp3(path + "/verb/" + m_verbs[m_verb].main + ".ts." + m_verbs[m_verb].third_singular + ".mp3"),
      will_mp3(path + "/auxiliary/will.mp3"),
      won_t_mp3(path + "/reduction/won_t.mp3")
      ;

    if (Past == m_time)
    {
      if (Question == m_sentence)
      {
        text += "did";  m_files.push_back(did_mp3);
        text += " ";
        text += Pronouns[m_pronoun]; m_files.push_back(pronoun_mp3);
        text += " ";
        text += m_verbs[m_verb].main;  m_files.push_back(verb_mp3);
        text += "?";
      }
      else if (Statement == m_sentence)
      {
        text += Pronouns[m_pronoun];  m_files.push_back(pronoun_mp3);
        text += " ";
        text += m_verbs[m_verb].past;  m_files.push_back(verb_past_mp3);
      }
      else if (Negation == m_sentence)
      {
        text += Pronouns[m_pronoun];  m_files.push_back(pronoun_mp3);
        text += " ";
        text += "didn't";  m_files.push_back(didn_t_mp3);
        text += " ";
        text += m_verbs[m_verb].main;  m_files.push_back(verb_mp3);
      }
    }
    else if (Present == m_time)
    {
      const bool third_singular(He == m_pronoun || She == m_pronoun);
      if (Question == m_sentence)
      {
        text += third_singular? "does": "do";  m_files.push_back(third_singular? does_mp3: do_mp3);
        text += " ";
        text += Pronouns[m_pronoun];  m_files.push_back(pronoun_mp3);
        text += " ";
        text += m_verbs[m_verb].main;  m_files.push_back(verb_mp3);
        text += "?";
      }
      else if (Statement == m_sentence)
      {
        text += Pronouns[m_pronoun];  m_files.push_back(pronoun_mp3);
        text += " ";
        text += third_singular? m_verbs[m_verb].third_singular: m_verbs[m_verb].main;  m_files.push_back(third_singular? verb_third_singular_mp3: verb_mp3);
      }
      else if (Negation == m_sentence)
      {
        text += Pronouns[m_pronoun];  m_files.push_back(pronoun_mp3);
        text += " ";
        text += third_singular? "doesn't": "don't";  m_files.push_back(third_singular? doesn_t_mp3: don_t_mp3);
        text += " ";
        text += m_verbs[m_verb].main;  m_files.push_back(verb_mp3);
      }
    }
    else if (Future == m_time)
    {
      if (Question == m_sentence)
      {
        text += "will";  m_files.push_back(will_mp3);
        text += " ";
        text += Pronouns[m_pronoun];  m_files.push_back(pronoun_mp3);
        text += " ";
        text += m_verbs[m_verb].main;  m_files.push_back(verb_mp3);
        text += "?";
      }
      else if (Statement == m_sentence)
      {
        text += Pronouns[m_pronoun];  m_files.push_back(pronoun_ll_mp3);
        text += "'ll";
        text += " ";
        text += m_verbs[m_verb].main;  m_files.push_back(verb_mp3);
      }
      else if (Negation == m_sentence)
      {
        text += Pronouns[m_pronoun];  m_files.push_back(pronoun_mp3);
        text += " ";
        text += "won't";  m_files.push_back(won_t_mp3);
        text += " ";
        text += m_verbs[m_verb].main;  m_files.push_back(verb_mp3);
      }
    }

    m_answer = m_task;

    item->setText(text);
    item->setForeground(QBrush(Qt::darkGreen));
    on_finished();
    timerEvent((QTimerEvent*)0);
  }

  ui->matrix->setItem(m_sentence, m_time, item);
  m_done = !m_done;
  ui->repeat->setEnabled(m_done);
}

void MainWidget::on_finished()
{
  if (m_files.empty()) return;
  m_media->setCurrentSource(Phonon::MediaSource(m_files.front()));
  m_files.pop_front();
  m_media->play();
}

void MainWidget::on_next_clicked()
{
  step();
}

void MainWidget::on_repeat_clicked()
{
  m_done = false;
  step();
}

void MainWidget::on_matrix_doubleClicked(const QModelIndex &index)
{
  if ( (index.column() >= 0 && index.column() != m_time)
    || (index.row() >= 0 && index.row() != m_sentence))
    m_done = true;
  step(index.column(), index.row());
}

void MainWidget::timerEvent(QTimerEvent*)
{
  setWindowTitle( QString().setNum(m_answer) + ", " + QString().setNum((double)m_qtime.elapsed() / 1000., 'f', 1) );
}
